package model.pieces;

import java.awt.Point;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import utils.PlayerSides;

import model.Board;

/**
 * Class represents a Knight Piece in chess game. Can move 2 steps to any direction and another single step in 90-degree turn
 */
public class Knight extends Piece {

	// private methods
	
	/**
	 * Gets all reachable free positions of a Knight piece on current turn, and removes positions that exceed
	 * the board's bounds
	 * @param gameBoard- chess game board
	 * @param freePositions- Knight's reachable free positions on current turn 
	 */
	private void filterOutOfBoundPositions(Board gameBoard, List<Point> freePositions) {

		// get an iterator for the list
		Iterator<Point> iter = freePositions.iterator();
		
		// scan list and remove positions that exceed board's bounds
		while (iter.hasNext()) {
			
			// check if current position is occupied
			Point currPosition = new Point(iter.next());
			if (gameBoard.notValidPosition(currPosition.x, currPosition.y)) {
				
				// remove current position
				iter.remove();
			}
		}
	}
	
	/**
	 * Gets all reachable free positions of a Knight piece on current turn, and removes positions that hold
	 * other pieces
	 * @param gameBoard- chess game board
	 * @param freePositions- Knight's reachable free positions on current turn
	 */
	private void filterOccupiedPositions(Board gameBoard, List<Point> freePositions) {

		// get an iterator for the list
		Iterator<Point> iter = freePositions.iterator();
		
		// scan list and remove occupied positions
		while (iter.hasNext()) {
			
			// check if current position is occupied
			Point currPosition = new Point(iter.next());
			if (gameBoard.getPiece(currPosition.x, currPosition.y) != null) {
				
				// remove current position
				iter.remove();
			}
		}
	}
	
	/**
	 * Gets all reachable positions of a Knight piece on current turn, and removes positions that hold
	 * friendly pieces
	 * @param gameBoard- chess game board
	 * @param opponentPositions- Knight's reachable positions on current turn that hold opponent pieces
	 */
	private void filterFriendlyPiecesPositions(Board gameBoard, List<Point> opponentPositions) {

		// get an iterator for the list
		Iterator<Point> iter = opponentPositions.iterator();
		
		// scan list and remove occupied positions
		while (iter.hasNext()) {
			
			// check if current position is occupied
			Point currPosition = new Point(iter.next());
			if (gameBoard.getPiece(currPosition.x, currPosition.y) != null && gameBoard.getPiece(currPosition.x, currPosition.y).sameSide(this)) {
				
				// remove current position
				iter.remove();
			}
		}
	}
	
	// protected methods
	
	/**
	 * Gets reference to the game board and Knights's current position on board.
     * Returns a list of free positions that can be reached by making 2 steps to any 
     * direction and another single step in 90-degree turn.
     * Can "jump over" other pieces
	 */
	@Override
	protected List<Point> getAvailableFreePositions(Board gameBoard, Point srcPoint) {

		// initialize free reachable positions list
		List<Point> freePositions = new LinkedList<Point>();
		
		// check each step combination, and if valid and free- add destination position to list
		
		int[] bigSteps = {-2, 2};
		int[] smallSteps = {-1,1};
		
		// choose long step
		for (int i : bigSteps) {
			
			// change X-axis
			Point xAxisMove = new Point(srcPoint.x, srcPoint.y);
			xAxisMove.translate(i, 0);
			
			
			// change Y-axis
			Point yAxisMove = new Point(srcPoint.x, srcPoint.y);
			yAxisMove.translate(0, i);
			
			// complete the path
			for (int j : smallSteps) {
				
				// change Y-axis position
				Point currChange = new Point(xAxisMove);
				currChange.translate(0, j);
				
				// add the reachable position
				freePositions.add(currChange);
				
				// change X-axis position
				currChange = new Point(yAxisMove);
				currChange.translate(j, 0);
				
				// add the reachable position
				freePositions.add(currChange);
			}
		}
		
		// filter out positions that exceed board's bounds
		filterOutOfBoundPositions(gameBoard, freePositions);
		
		// filter out occupied positions
		filterOccupiedPositions(gameBoard, freePositions);
	
		// return list with all valid free positions
		return freePositions;
	}

	/**
	 * Gets reference to the game board and Knights's current position on board.
     * Returns a list of positions holding opponent's pieces, that can be reached by making 2 steps to any 
     * direction and another single step in 90-degree turn.
     * Can "jump over" other pieces
	 */
	@Override
	protected List<Point> getAvailableOpponentPositions(Board gameBoard, Point srcPoint) {
		
		// initialize list of reachable opponent's positions
		List<Point> opponentPositions = new LinkedList<Point>();

		// check each step combination, and if valid and holds opponent's piece- add destination position to list
		int[] bigSteps = {-2, 2};
		int[] smallSteps = {-1,1};
		
		// choose long step
		for (int i : bigSteps) {
			
			// change X-axis
			Point xAxisMove = new Point(srcPoint.x, srcPoint.y);
			xAxisMove.translate(i, 0);
			
			
			// change Y-axis
			Point yAxisMove = new Point(srcPoint.x, srcPoint.y);
			yAxisMove.translate(0, i);
			
			// complete the path
			for (int j : smallSteps) {
				
				// change Y-axis position
				Point currChange = new Point(xAxisMove);
				currChange.translate(0, j);
				
				// add the reachable position
				opponentPositions.add(currChange);
				
				// change X-axis position
				currChange = new Point(yAxisMove);
				currChange.translate(j, 0);
				
				// add the reachable position
				opponentPositions.add(currChange);
			}
		}
		
		// filter out positions that exceed board's bounds
		filterOutOfBoundPositions(gameBoard, opponentPositions);
		
		// filter out positions with friendly pieces
		filterFriendlyPiecesPositions(gameBoard, opponentPositions);
		
		// return list of position in range found
		return opponentPositions;
	}
	
	// public methods
	
	/**
	 * Constructor- creates a new Bishop assigned to given player
	 * @param side-  indicates piece's player
	 */
	public Knight(PlayerSides.Sides side) {
		super(side);
	}

	/**
	 * Returns a Knight of the same team
	 */
	@Override
	public Piece clone() { return new Knight(super.getPlayer()); }
}